home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / ADVANCED / CSG.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  7.0 KB  |  344 lines

  1.  
  2. /* csg.c - by Tom McReynolds, SGI */
  3.  
  4. /* Doing constructive solid geometry (CSG) with stencil. */
  5.  
  6. #include <GL/glut.h>
  7. #include <stdlib.h>
  8. #include <math.h>
  9.  
  10. enum {
  11.   CSG_A, CSG_B, CSG_A_OR_B, CSG_A_AND_B, CSG_A_SUB_B, CSG_B_SUB_A
  12. };
  13.  
  14. /* just draw single object */
  15. void
  16. one(void (*a) (void))
  17. {
  18.   glEnable(GL_DEPTH_TEST);
  19.   a();
  20.   glDisable(GL_DEPTH_TEST);
  21. }
  22.  
  23. /* "or" is easy; simply draw both objects with depth buffering on */
  24. void
  25. or(void (*a) (void), void (*b) (void))
  26. {
  27.   glEnable(GL_DEPTH_TEST);
  28.   a();
  29.   b();
  30.   glDisable(GL_DEPTH_TEST);
  31. }
  32.  
  33. /* Set stencil buffer to show the part of a (front or back face) that's
  34.    inside b's volume. Requirements: GL_CULL_FACE enabled, depth func GL_LESS
  35.    Side effects: depth test, stencil func, stencil op */
  36. void
  37. firstInsideSecond(void (*a) (void), void (*b) (void), GLenum face, GLenum test)
  38. {
  39.   glEnable(GL_DEPTH_TEST);
  40.   glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  41.   glCullFace(face);     /* controls which face of a to use */
  42.   a();                  /* draw a face of a into depth buffer */
  43.  
  44.   /* use stencil plane to find parts of a in b */
  45.   glDepthMask(GL_FALSE);
  46.   glEnable(GL_STENCIL_TEST);
  47.   glStencilFunc(GL_ALWAYS, 0, 0);
  48.   glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
  49.   glCullFace(GL_BACK);
  50.   b();                  /* increment the stencil where the front face of b is 
  51.                            drawn */
  52.   glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
  53.   glCullFace(GL_FRONT);
  54.   b();                  /* decrement the stencil buffer where the back face
  55.                            of b is drawn */
  56.   glDepthMask(GL_TRUE);
  57.   glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  58.  
  59.   glStencilFunc(test, 0, 1);
  60.   glDisable(GL_DEPTH_TEST);
  61.  
  62.   glCullFace(face);
  63.   a();                  /* draw the part of a that's in b */
  64. }
  65.  
  66. void
  67. fixDepth(void (*a) (void))
  68. {
  69.   glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  70.   glEnable(GL_DEPTH_TEST);
  71.   glDisable(GL_STENCIL_TEST);
  72.   glDepthFunc(GL_ALWAYS);
  73.   a();                  /* draw the front face of a, fixing the depth buffer */
  74.   glDepthFunc(GL_LESS);
  75. }
  76.  
  77. /* "and" two objects together */
  78. void
  79. and(void (*a) (void), void (*b) (void))
  80. {
  81.   firstInsideSecond(a, b, GL_BACK, GL_NOTEQUAL);
  82.  
  83.   fixDepth(b);
  84.  
  85.   firstInsideSecond(b, a, GL_BACK, GL_NOTEQUAL);
  86.  
  87.   glDisable(GL_STENCIL_TEST);  /* reset things */
  88. }
  89.  
  90. /* subtract b from a */
  91. void
  92. sub(void (*a) (void), void (*b) (void))
  93. {
  94.   firstInsideSecond(a, b, GL_FRONT, GL_NOTEQUAL);
  95.  
  96.   fixDepth(b);
  97.  
  98.   firstInsideSecond(b, a, GL_BACK, GL_EQUAL);
  99.  
  100.   glDisable(GL_STENCIL_TEST);  /* reset things */
  101. }
  102.  
  103. enum {
  104.   SPHERE = 1, CONE
  105. };
  106.  
  107. /* Draw a cone */
  108. GLfloat coneX = 0.f, coneY = 0.f, coneZ = 0.f;
  109. void
  110. cone(void)
  111. {
  112.   glPushMatrix();
  113.   glTranslatef(coneX, coneY, coneZ);
  114.   glTranslatef(0.f, 0.f, -30.f);
  115.   glCallList(CONE);
  116.   glPopMatrix();
  117. }
  118.  
  119. /* Draw a sphere */
  120. GLfloat sphereX = 0.f, sphereY = 0.f, sphereZ = 0.f;
  121. void
  122. sphere(void)
  123. {
  124.   glPushMatrix();
  125.   glTranslatef(sphereX, sphereY, sphereZ);
  126.   glCallList(SPHERE);
  127.   glPopMatrix();
  128.  
  129. }
  130.  
  131. int csg_op = CSG_A;
  132.  
  133. /* add menu callback */
  134.  
  135. void 
  136. menu(int csgop)
  137. {
  138.   csg_op = csgop;
  139.   glutPostRedisplay();
  140. }
  141.  
  142. GLfloat viewangle;
  143.  
  144. void 
  145. redraw(void)
  146. {
  147.   /* clear stencil each time */
  148.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  149.  
  150.   glPushMatrix();
  151.   glRotatef(viewangle, 0.f, 1.f, 0.f);
  152.  
  153.   switch (csg_op) {
  154.   case CSG_A:
  155.     one(cone);
  156.     break;
  157.   case CSG_B:
  158.     one(sphere);
  159.     break;
  160.   case CSG_A_OR_B:
  161.     or(cone, sphere);
  162.     break;
  163.   case CSG_A_AND_B:
  164.     and(cone, sphere);
  165.     break;
  166.   case CSG_A_SUB_B:
  167.     sub(cone, sphere);
  168.     break;
  169.   case CSG_B_SUB_A:
  170.     sub(sphere, cone);
  171.     break;
  172.   }
  173.   glPopMatrix();
  174.   glutSwapBuffers();
  175. }
  176.  
  177. /* animate scene by rotating */
  178. enum {
  179.   ANIM_LEFT, ANIM_RIGHT
  180. };
  181. int animDirection = ANIM_LEFT;
  182.  
  183. void 
  184. anim(void)
  185. {
  186.   if (animDirection == ANIM_LEFT)
  187.     viewangle -= 3.f;
  188.   else
  189.     viewangle += 3.f;
  190.   glutPostRedisplay();
  191. }
  192.  
  193. /* ARGSUSED1 */
  194. /* special keys, like array and F keys */
  195. void 
  196. special(int key, int x, int y)
  197. {
  198.   switch (key) {
  199.   case GLUT_KEY_LEFT:
  200.     glutIdleFunc(anim);
  201.     animDirection = ANIM_LEFT;
  202.     break;
  203.   case GLUT_KEY_RIGHT:
  204.     glutIdleFunc(anim);
  205.     animDirection = ANIM_RIGHT;
  206.     break;
  207.   case GLUT_KEY_UP:
  208.   case GLUT_KEY_DOWN:
  209.     glutIdleFunc(0);
  210.     break;
  211.   }
  212. }
  213.  
  214. /* ARGSUSED1 */
  215. void 
  216. key(unsigned char key, int x, int y)
  217. {
  218.   switch (key) {
  219.   case 'a':
  220.     viewangle -= 10.f;
  221.     glutPostRedisplay();
  222.     break;
  223.   case 's':
  224.     viewangle += 10.f;
  225.     glutPostRedisplay();
  226.     break;
  227.   case '\033':
  228.     exit(0);
  229.   }
  230. }
  231.  
  232. int picked_object;
  233. int xpos = 0, ypos = 0;
  234. int newxpos, newypos;
  235. int startx, starty;
  236.  
  237. void
  238. mouse(int button, int state, int x, int y)
  239. {
  240.   if (state == GLUT_UP) {
  241.     picked_object = button;
  242.     xpos += newxpos;
  243.     ypos += newypos;
  244.     newxpos = 0;
  245.     newypos = 0;
  246.   } else {              /* GLUT_DOWN */
  247.     startx = x;
  248.     starty = y;
  249.   }
  250. }
  251.  
  252. #define DEGTORAD (2 * 3.1415 / 360)
  253. void 
  254. motion(int x, int y)
  255. {
  256.   GLfloat r, objx, objy, objz;
  257.  
  258.   newxpos = x - startx;
  259.   newypos = starty - y;
  260.  
  261.   r = (newxpos + xpos) * 50.f / 512.f;
  262.   objx = r * cos(viewangle * DEGTORAD);
  263.   objy = (newypos + ypos) * 50.f / 512.f;
  264.   objz = r * sin(viewangle * DEGTORAD);
  265.  
  266.   switch (picked_object) {
  267.   case CSG_A:
  268.     coneX = objx;
  269.     coneY = objy;
  270.     coneZ = objz;
  271.     break;
  272.   case CSG_B:
  273.     sphereX = objx;
  274.     sphereY = objy;
  275.     sphereZ = objz;
  276.     break;
  277.   }
  278.   glutPostRedisplay();
  279. }
  280.  
  281. int
  282. main(int argc, char **argv)
  283. {
  284.   static GLfloat lightpos[] =
  285.   {25.f, 50.f, -50.f, 1.f};
  286.   static GLfloat sphere_mat[] =
  287.   {1.f, .5f, 0.f, 1.f};
  288.   static GLfloat cone_mat[] =
  289.   {0.f, .5f, 1.f, 1.f};
  290.   GLUquadricObj *sphere, *cone, *base;
  291.  
  292.   glutInit(&argc, argv);
  293.   glutInitWindowSize(512, 512);
  294.   glutInitDisplayMode(GLUT_STENCIL | GLUT_DEPTH | GLUT_DOUBLE);
  295.   (void) glutCreateWindow("csg");
  296.   glutDisplayFunc(redraw);
  297.   glutKeyboardFunc(key);
  298.   glutSpecialFunc(special);
  299.   glutMouseFunc(mouse);
  300.   glutMotionFunc(motion);
  301.  
  302.   glutCreateMenu(menu);
  303.   glutAddMenuEntry("A only", CSG_A);
  304.   glutAddMenuEntry("B only", CSG_B);
  305.   glutAddMenuEntry("A or B", CSG_A_OR_B);
  306.   glutAddMenuEntry("A and B", CSG_A_AND_B);
  307.   glutAddMenuEntry("A sub B", CSG_A_SUB_B);
  308.   glutAddMenuEntry("B sub A", CSG_B_SUB_A);
  309.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  310.  
  311.   glEnable(GL_CULL_FACE);
  312.   glEnable(GL_LIGHTING);
  313.   glEnable(GL_LIGHT0);
  314.  
  315.   glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
  316.   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
  317.  
  318.   /* make display lists for sphere and cone; for efficiency */
  319.  
  320.   glNewList(SPHERE, GL_COMPILE);
  321.   sphere = gluNewQuadric();
  322.   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, sphere_mat);
  323.   gluSphere(sphere, 20.f, 64, 64);
  324.   gluDeleteQuadric(sphere);
  325.   glEndList();
  326.  
  327.   glNewList(CONE, GL_COMPILE);
  328.   cone = gluNewQuadric();
  329.   base = gluNewQuadric();
  330.   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, cone_mat);
  331.   gluQuadricOrientation(base, GLU_INSIDE);
  332.   gluDisk(base, 0., 15., 64, 1);
  333.   gluCylinder(cone, 15., 0., 60., 64, 64);
  334.   gluDeleteQuadric(cone);
  335.   gluDeleteQuadric(base);
  336.   glEndList();
  337.  
  338.   glMatrixMode(GL_PROJECTION);
  339.   glOrtho(-50., 50., -50., 50., -50., 50.);
  340.   glMatrixMode(GL_MODELVIEW);
  341.   glutMainLoop();
  342.   return 0;             /* ANSI C requires main to return int. */
  343. }
  344.